﻿namespace FluentMvc
{
    using System.Collections.Generic;
    using System.Linq;
    using System.Web.Mvc;

    public class ModelValidator<TModel> where TModel : class
    {
        private readonly ModelContext<TModel> modelContext;

        public ModelValidator(ModelContext<TModel> modelContext)
        {
            this.modelContext = modelContext;
        }

        public IEnumerable<ModelValidationResult> ValidateProperty(string propertyName, object propertyValue, TModel model)
        {
            var validationResults = new List<ModelValidationResult>();  
            var propertySettings = modelContext.GetSettings(propertyName);
            if (propertySettings == null)
                return Enumerable.Empty<ModelValidationResult>();
            var validationContext = new FluentValidationContext(model, propertyName, propertyValue);
            if (MvcIntegration.FluentValidatorProvider.BeforeValidate != null)
                MvcIntegration.FluentValidatorProvider.BeforeValidate(validationContext);
            if (propertySettings.BeforeValidate != null)
                propertySettings.BeforeValidate(validationContext);
            foreach (var setting in propertySettings.ValidationSettings)
            {
                if (setting.When != null && !setting.When(model))
                    continue;
                if (setting.Ignore != null && setting.Ignore(model))
                    continue;
                if (setting.CustomValidation != null && setting.CustomValidation(model))
                    continue;                
                if (setting.Rule != null && setting.Rule.Validate(validationContext))
                    continue;
                string errorMessage;
                if (setting.Message != null)
                    errorMessage = setting.Message;
                else if (setting.GetMessage != null)
                    errorMessage = setting.GetMessage();
                else
                    errorMessage = null;
                validationResults.Add(new ModelValidationResult
                                          {
                                              MemberName = setting.PropertyName,
                                              Message = errorMessage
                                          });
                if (setting.StopChainOnFail)
                    break;
            }
            var afterValidateArgs = new AfterValidateArgs
                                        {
                                            IsValid = validationResults.Count == 0,
                                            ValidationContext = validationContext,
                                            ValidationResults = validationResults
                                        };
            if (MvcIntegration.FluentValidatorProvider.AfterValidate != null)
                MvcIntegration.FluentValidatorProvider.AfterValidate(afterValidateArgs);
            if (propertySettings.AfterValidate != null)
                propertySettings.AfterValidate(afterValidateArgs);
            return validationResults;
        }
    }
}